import OpenAI from "openai";

/**
 * 函数调用示例
 * 这个示例展示了如何使用 OpenAI API 的函数调用功能
 * 主要功能：
 * 1. 定义可调用的函数及其参数
 * 2. 处理用户问题并调用相应函数
 * 3. 递归处理函数调用结果
 * 
 * @param question - 用户的问题，默认值包含天气查询和主播信息查询
 */
export async function functionCallingSample(question:string = "余奇在长沙，他当前所在地天气如何？并且他是大主播吗?,给出他的具体的粉丝数，与结论"){
  try{
    console.log("function_calling running")
    // 初始化 OpenAI 客户端
    const openai = new OpenAI(
      {
          // 配置 API 密钥和基础 URL
          // 注意：这里使用的是阿里云百炼的 API
          apiKey: "sk-1e36e14fe6fa45c5a8f314c408f1ae39",
          baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
      }
    );

    // 初始化对话消息数组
    const messages:any[] = [
      { role: "user", content: question }
    ]

    // 定义可调用的函数列表
    const functions=[
      {
        // 获取天气信息的函数定义
        name:'get_weather_in_loaction',
        description:'获取天气信息数据',
        parameters:{
          type:'object',
          properties:{
              location:{
              type:'string',
              description:"获取天气数据的地点"
            }
          }
        },
      },
      {
        // 获取主播粉丝数的函数定义
        name:'get_fans_count_by_name',
        description:'根据UP主名子返回用户的粉丝数',
        parameters:{
          type:'object',
          properties:{
              upname:{
              type:'string',
              description:"主播名字"
            }
          }
        },
      },
      {
        // 判断是否为大主播的函数定义
        name:'isKOA',
        description:'根据粉丝数，返回UP是不是大主播',
        parameters:{
          type:'object',
          properties:{
            "fanseCount":{
              type:"number",
              description:"获取天气数据的地点"
            }
          }
        },
      }
    ]

    // 定义函数映射表，将函数名映射到实际实现
    const functionsMap:Record<string,Function>={
      // 天气查询函数实现
      "get_weather_in_loaction":function(data:{location:string,unit?:string}){
        return {
          location:data.location,
          temperature:22,
          unit:data.unit,
          forecast:["晴天", "微风"]
        }
      },
      // 粉丝数查询函数实现
      "get_fans_count_by_name":function(data:{name:string}){
        return {
          count:Math.round(Math.random()*99),
        }
      },
      // 大主播判断函数实现
      "isKOA":function(data:{fanseCount:number}){
        return {
          isBig:data.fanseCount>2 ? true :false
        }
      }
    }

    /**
     * 递归处理 API 响应的函数
     * 1. 发送请求到 API
     * 2. 处理函数调用
     * 3. 递归处理直到得到最终答案
     * 
     * @param messages - 对话消息历史
     */
    async function getResponse(messages:any[]){
      try{
        // 调用 OpenAI API
        const completion = await openai.chat.completions.create({
            model: "qwen-turbo",  // 使用通义千问模型
            functions:functions,
            messages: messages,
        });

        // 处理 API 响应
        if(completion?.choices?.[0]?.message){
          // 将 API 响应添加到消息历史
          messages.push(completion?.choices?.[0]?.message);
          
          // 如果响应包含函数调用
          if(messages.slice(-1)[0]['function_call']){
            // 执行函数调用
            const functionResponse = functionsMap[messages.slice(-1)[0].function_call.name as string]?.(
              JSON.parse(messages.slice(-1)[0].function_call.arguments)
            );
            
            // 将函数执行结果添加到消息历史
            messages.push({
              "role": "function", 
              "name": messages.slice(-1)[0].function_call.name, 
              "content": JSON.stringify(functionResponse)
            });
            
            // 递归处理，直到得到最终答案
            getResponse(messages);
          }else{
            // 如果没有函数调用，输出最终答案
            console.log("\n")
            console.log('------------------------------------------------')
            console.log(messages.pop().content)
          }
        }
      }catch(err){
        console.log(err);
      }
    }

    // 开始处理用户问题
    getResponse(messages)
    
  }catch(err){
    console.log(err)
  }
}